import os
import configparser
import socket
import threading


class ReadConfig:
    def __init__(self, ConfgPath: str):
        self.ConfgPath = ConfgPath
        self.classprint = "Server ReadConfig:"
        # 创建 ConfigParser 实例，用来解析 config.ini
        self.conf = configparser.ConfigParser()
        self.conf.read(ConfgPath)

        # 获取所有 sections
        self.sections = self.conf.sections()
        print(self.classprint,ConfgPath)
        print(self.classprint,"config目前的字段")
        for section in self.sections:
            print(self.classprint,section)
        print("=============")
    def get_LISTEN_PORT(self):
        return int(self.conf.get("DEFAULT","LISTEN_PORT"))

    def get_LISTEN_MAX(self):
        return int(self.conf.get("DEFAULT","LISTEN_MAX"))

    def get_AllAPP(self):
        return self.sections

    def get_BACKEND_PORT(self,sectionName):
        return self.conf.get(sectionName,"BACKEND_PORT")

    def get_FEATURE(self,sectionName):
        return self.conf.get(sectionName,"FEATURE")

    def test(self):
        config = ReadConfig("./config2.0.ini")
        print(config.get_LISTEN_PORT())
        print(config.get_AllAPP())
        print(config.get_BACKEND_PORT("APP-MC1"))
        print(config.get_FEATURE("APP-MC1"))

class PortDeal:
    def __init__(self,config:ReadConfig):
        self.config=config
        self.port = self.config.get_LISTEN_PORT()
        self.ip="0.0.0.0"
        self.App=config.get_AllAPP()


    def catPortPack(self):
        srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # 创建 TCP socket
        srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)  # 地址复用，方便调试快速重启
        srv.bind((self.ip, self.port))  # 绑定监听地址和端口
        srv.listen(self.config.get_LISTEN_MAX())  # 开始监听，最大挂起连接队列 128
        print("代理已启动，监听 {}:{} ".format(
            self.ip, self.port))
        # 主循环：阻塞等待新连接，每来一个就创建线程处理
        while True:
            cli, addr = srv.accept()  # accept() 返回 (新套接字, 对端地址)
            threading.Thread(target=self.handle, args=(cli, addr)).start()  # 把 handle 函数跑在独立线程里

    # -------------- 工具函数：把一端的数据原封不动“管道”到另一端 --------------
    def pipe(self,src, dst):
        """
        把 src socket 收到的所有字节流透传给 dst socket。
        任意一端关闭或出错都会退出循环，并关闭两端 socket。
        """
        try:
            while True:  # 持续转发直到 EOF
                buf = src.recv(4096)  # 一次最多收 4 KB
                if not buf:  # 返回空串表示对端已关闭
                    break
                dst.sendall(buf)  # 保证全部发出去（sendall 会循环 send）
        except socket.error:  # 出现 TCP 错误时静默结束
            pass
        finally:  # 无论正常结束还是异常，都要关闭两端
            src.close()
            dst.close()

    # -------------- 处理单个客户端连接的线程函数 --------------
    def handle(self,cli_sock, cli_addr):
        """
        每个新连接都会启动一个独立线程执行此函数。
        1. 先读首包，检查是否包含“特征串”；
        2. 如果匹配就把后续流量桥接到后端；不匹配就丢弃。
        """
        try:
            first = cli_sock.recv(4096)  # 读取客户端发来的首包，最多 1 KB
            for app in self.App:
                BACKEND_PORT=self.config.get_BACKEND_PORT(app)
                FEATURE=self.config.get_FEATURE(app)

                # 检查数据长度是否足够
                if len(first) < 15:
                    print("接收的数据不足15字节")
                    return None
                else:
                    # 获取数据部分的最后15个字节
                    last_16_bytes = first[-15:].hex()
                    # 如果查找到特征
                    if last_16_bytes.find(FEATURE)!=-1:
                        print("后端端口:",str(BACKEND_PORT))
                        #删除54 61 72 67 65 74 50 6f 72 74和后面的全部数据
                        first=first[:last_16_bytes.find(FEATURE)]

                        # 如果包含特征串，则视为合法流量，准备桥接
                        print("{} 匹配，桥接到 {}:{}".format(cli_addr, self.ip, BACKEND_PORT))
                        be_sock = socket.create_connection((self.ip, BACKEND_PORT))  # 主动连后端
                        be_sock.sendall(first)  # 把首包先发过去

                        # 启动两条“管道”线程，实现全双工转发
                        threading.Thread(target=self.pipe, args=(cli_sock, be_sock)).start()  # 客户端 → 后端
                        threading.Thread(target=self.pipe, args=(be_sock, cli_sock)).start()  # 后端 → 客户端
                    else:
                        print("交付{}端口服务处理".format(self.config.get("DEFAULT","DEFINE_PORT")))


        except Exception as e:
            print("异常: {}".format(e))  # 打印异常信息
            cli_sock.close()  # 关闭客户端 socket，防止句柄泄漏
if __name__ == '__main__':
    """
    数据报尾部：
    TargetPort25565
    54 61 72 67 65 74 50 6f 72 74 32 35 35 36 35
    TargetPort
    54 61 72 67 65 74 50 6f 72 74
    """
    print()
    config=ReadConfig("./config2.0.ini")
    pd=PortDeal(config)
    pd.catPortPack()
